package com.hina.rec.application.service.system.impl;

import cn.hutool.core.collection.CollUtil;
import cn.idev.excel.EasyExcel;
import cn.idev.excel.read.listener.PageReadListener;
import cn.idev.excel.support.ExcelTypeEnum;
import cn.idev.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hina.rec.application.convert.system.SettleDetailConvert;
import com.hina.rec.application.manager.SettleDetailManager;
import com.hina.rec.application.service.system.SettleDetailService;
import com.hina.rec.common.handler.CustomCellStyleWriteHandler;
import com.hina.rec.common.model.IdReq;
import com.hina.rec.common.utils.AssertUtil;
import com.hina.rec.domain.model.SettleDetailBO;
import com.hina.rec.domain.model.SettleDetailDO;
import com.hina.rec.endpoint.req.system.SettleDetailPageReq;
import com.hina.rec.endpoint.req.system.SettleDetailSaveReq;
import com.hina.rec.endpoint.req.system.SettleDetailUpdateReq;
import com.hina.rec.endpoint.res.base.PageRes;
import com.hina.rec.endpoint.res.system.SettleDetailRes;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

/**
 * 结算明细Service实现类
 *
 * @author liaosp
 * @date 2024-01-05
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SettleDetailServiceImpl implements SettleDetailService {

    private final SettleDetailManager settleDetailManager;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean save(SettleDetailSaveReq req) {
        SettleDetailDO settleDetailDO = SettleDetailConvert.INSTANCE.toSettleDetailDO(req);
        return settleDetailManager.save(settleDetailDO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean update(SettleDetailUpdateReq req) {
        SettleDetailDO settleDetailDO = settleDetailManager.getById(req.getId());
        AssertUtil.notNull(settleDetailDO, "结算明细不存在");
        settleDetailDO = SettleDetailConvert.INSTANCE.toSettleDetailDO(req);
        return settleDetailManager.updateById(settleDetailDO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean delete(Integer id) {
        SettleDetailDO settleDetailDO = settleDetailManager.getById(id);
        AssertUtil.notNull(settleDetailDO, "结算明细不存在");
        return settleDetailManager.removeById(id);
    }

    @Override
    public PageRes<SettleDetailRes> page(SettleDetailPageReq req) {
        Page<SettleDetailDO> page = new Page<>(req.getPageNum(), req.getPageSize());
        LambdaQueryWrapper<SettleDetailDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(req.getYear() != null, SettleDetailDO::getYear, req.getYear())
                .eq(req.getMonth() != null, SettleDetailDO::getMonth, req.getMonth())
                .like(StringUtils.isNotBlank(req.getSettleName()), SettleDetailDO::getSettleName, req.getSettleName())
                .like(StringUtils.isNotBlank(req.getBatchName()), SettleDetailDO::getBatchName, req.getBatchName())
                .like(StringUtils.isNotBlank(req.getSencMemberId()), SettleDetailDO::getSencMemberId, req.getSencMemberId())
                .like(StringUtils.isNotBlank(req.getSencMemberName()), SettleDetailDO::getSencMemberName, req.getSencMemberName())
                .like(StringUtils.isNotBlank(req.getSubProductName()), SettleDetailDO::getSubProductName, req.getSubProductName())
                .like(StringUtils.isNotBlank(req.getSubProductType()), SettleDetailDO::getSubProductType, req.getSubProductType())
                .eq(StringUtils.isNotBlank(req.getEnvironment()), SettleDetailDO::getEnvironment, req.getEnvironment())
                .eq(StringUtils.isNotBlank(req.getVerifyStatus()), SettleDetailDO::getVerifyStatus, req.getVerifyStatus())
                .orderByDesc(SettleDetailDO::getCreatedAt);
        page = settleDetailManager.page(page, queryWrapper);
        return PageRes.fromPage(page, SettleDetailConvert.INSTANCE::toSettleDetailRes);
    }

    @Override
    public SettleDetailRes detail(IdReq req) {
        SettleDetailDO settleDetailDO = settleDetailManager.getById(req.getId());
        AssertUtil.notNull(settleDetailDO, "结算明细不存在");
        return SettleDetailConvert.INSTANCE.toSettleDetailRes(settleDetailDO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean importExcel(MultipartFile file) throws IOException {
        List<SettleDetailDO> list = new ArrayList<>();
        List<SettleDetailBO> detailList = new ArrayList<>();
        // 读取从第2个sheet页（索引从1开始）到最后一个sheet页的所有数据
        EasyExcel.read(file.getInputStream(), SettleDetailBO.class, new PageReadListener<SettleDetailBO>(dataList -> {
            detailList.addAll(dataList);
        }))
        .sheet(1)  // 从第2个sheet页开始（索引从0开始）
        .headRowNumber(5)  // 从第5行开始读取数据（跳过前4行）
        .doRead();
        
        // 获取Excel文件中的sheet数量
        int sheetCount = EasyExcel.read(file.getInputStream()).build().excelExecutor().sheetList().size();
        
        // 读取第3个sheet页及之后的所有sheet页（如果存在）
        for (int i = 2; i < sheetCount; i++) {
            EasyExcel.read(file.getInputStream(), SettleDetailBO.class, new PageReadListener<SettleDetailBO>(dataList -> {
                detailList.addAll(dataList);
            }))
            .sheet(i)  // 读取指定索引的sheet页
            .headRowNumber(5)  // 从第5行开始读取数据（跳过前4行）
            .doRead();
        }

        if (CollUtil.isEmpty(list)) {
            return false;
        }
        
        // 从文件名中提取结算单名称
        String fileName = file.getOriginalFilename();
        String settleName = fileName;
        if (fileName != null && fileName.contains(".")) {
            settleName = fileName.substring(0, fileName.lastIndexOf("."));
        }
        
        // 解析文件名中的批次信息
        // 例如："对账单2024年1、2月第四批和3、4、6月第三批和5月第五批和7、8、9月第二批"
        // 存储月份和批次的对应关系
        java.util.Map<Integer, String> monthToBatchMap = new java.util.HashMap<>();
        
        if (fileName != null) {
            // 使用正则表达式匹配所有的月份和批次信息
            java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("(\\d+)(?:、(\\d+))*月第([一二三四五六七八九十]+)批");
            java.util.regex.Matcher matcher = pattern.matcher(settleName);
            
            while (matcher.find()) {
                String batchName = "第" + matcher.group(3) + "批";
                
                // 处理主月份
                int month = Integer.parseInt(matcher.group(1));
                // 月份可能是个位数，需要转为两位数格式
                monthToBatchMap.put(month, batchName);
                
                // 处理可能存在的其他月份（用、分隔的）
                if (matcher.group(2) != null) {
                    String[] additionalMonths = matcher.group(0).split("月")[0].split("、");
                    for (int i = 1; i < additionalMonths.length; i++) {
                        int additionalMonth = Integer.parseInt(additionalMonths[i]);
                        monthToBatchMap.put(additionalMonth, batchName);
                    }
                }
            }
        }

        SettleDetailDO settleDetailDO;
        // 为每一行数据从其第0列提取年份和月份
        for (SettleDetailBO detail : detailList) {
            settleDetailDO = new SettleDetailDO();
            // 设置结算单名称
            settleDetailDO.setSettleName(settleName);
            
            // 从每行的第0列提取年份和月份
            String dateStr = detail.getCallDate(); // 假设第0列是调用日期，存储在sencMemberId字段
            if (dateStr != null && dateStr.matches("\\d{4}/\\d{2}/\\d{2}-\\d{4}/\\d{2}/\\d{2}")) {
                // 格式如：2024/01/01-2024/01/31
                String[] parts = dateStr.split("-");
                if (parts.length > 0) {
                    String[] dateParts = parts[0].split("/");
                    if (dateParts.length >= 2) {
                        Integer year = Integer.parseInt(dateParts[0]);
                        Integer month = Integer.parseInt(dateParts[1]);
                        
                        // 设置当前行的年份和月份
                        settleDetailDO.setYear(year);
                        settleDetailDO.setMonth(month);
                        
                        // 根据月份设置批次名
                        // 如果是01、02这样的格式，需要转换为整数1、2
                        int monthValue = month;
                        if (monthToBatchMap.containsKey(monthValue)) {
                            settleDetailDO.setBatchName(monthToBatchMap.get(monthValue));
                        }
                    }
                }
            }

            list.add(settleDetailDO);
        }
        
        return settleDetailManager.saveBatch(list);
    }

    @Override
    public void exportExcel(HttpServletResponse response, SettleDetailPageReq req) throws IOException {
        // 构建查询条件
        LambdaQueryWrapper<SettleDetailDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(req.getYear() != null, SettleDetailDO::getYear, req.getYear())
                .eq(req.getMonth() != null, SettleDetailDO::getMonth, req.getMonth())
                .like(StringUtils.isNotBlank(req.getSettleName()), SettleDetailDO::getSettleName, req.getSettleName())
                .like(StringUtils.isNotBlank(req.getBatchName()), SettleDetailDO::getBatchName, req.getBatchName())
                .like(StringUtils.isNotBlank(req.getSencMemberId()), SettleDetailDO::getSencMemberId, req.getSencMemberId())
                .like(StringUtils.isNotBlank(req.getSencMemberName()), SettleDetailDO::getSencMemberName, req.getSencMemberName())
                .like(StringUtils.isNotBlank(req.getSubProductName()), SettleDetailDO::getSubProductName, req.getSubProductName())
                .like(StringUtils.isNotBlank(req.getSubProductType()), SettleDetailDO::getSubProductType, req.getSubProductType())
                .eq(StringUtils.isNotBlank(req.getEnvironment()), SettleDetailDO::getEnvironment, req.getEnvironment())
                .eq(StringUtils.isNotBlank(req.getVerifyStatus()), SettleDetailDO::getVerifyStatus, req.getVerifyStatus())
                .orderByDesc(SettleDetailDO::getCreatedAt);

        // 查询数据
        List<SettleDetailDO> list = settleDetailManager.list(queryWrapper);

        // 设置响应头
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        String fileName = URLEncoder.encode("结算明细", StandardCharsets.UTF_8).replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");

        // 导出Excel
        EasyExcel.write(response.getOutputStream(), SettleDetailDO.class)
                .excelType(ExcelTypeEnum.XLSX)
                .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                .registerWriteHandler(new CustomCellStyleWriteHandler())
                .sheet("结算明细")
                .doWrite(list);
    }
}